/*
 *  xmpp_connection.cc
 *  wonderland-project
 *
 *  Created by Ben Nolan on 14/10/08.
 *  Copyright 2008 Nolan Consulting Limited. All rights reserved.
 *
 */

#include "xmpp_connection.h"
#include <iostream>

// Resolve shitty unresolved externs
const std::string gloox::GLOOX_VERSION = "1.0";
const std::string gloox::EmptyString = "";

namespace Wonderland{

  XmppConnection::XmppConnection(){
    server_ = "wonderlandproject.info";
	connected_ = false;
	authenticated_ = false;
  }

  void XmppConnection::createAccount(){
    registration_mode_ = true;
    connected_ = false;
    authenticated_ = false;
  
    using namespace gloox;
    
    jid_ = gloox::JID(nickname_ + "@" + server_);

    j = new Client(server_);

    j->setPort(5222);
    j->setServer(server_);
    j->setTls(gloox::TLSDisabled);
    j->disableRoster();
    j->setPresence( Presence::Chat, 5 );
    j->disco()->setVersion( "messageTest", GLOOX_VERSION, "Linux" );
    j->disco()->setIdentity( "client", "bot" );

    registration_ = new Registration( j );
    registration_->registerRegistrationHandler( this );

    j->registerConnectionListener( this );
    j->registerMessageHandler( this );
    j->registerPresenceHandler( this );
    j->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );

    if( j->connect(false) ){
      ce_ = ConnNoError;
      connected_=true;
    }else{
      signal_error("Could not connect");
    }
    
  }
  
  void XmppConnection::connect(){
    registration_mode_ = false;
    connected_ = false;
    authenticated_ = false;
    
    using namespace gloox;
    
    jid_ = gloox::JID(nickname_ + "@" + server_ + "/wonderland-viewer");
    
    j = new Client( jid_, password_ );

    j->setPort(5222);
    j->setServer(server_);
    j->setTls(gloox::TLSDisabled);
    j->disableRoster();
    j->setPresence( Presence::Chat, 5 );
    j->disco()->setVersion( "messageTest", GLOOX_VERSION, "Linux" );
    j->disco()->setIdentity( "client", "bot" );

    j->registerConnectionListener( this );
    j->registerMessageHandler( this );
    j->registerPresenceHandler( this );
    j->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );

    if( j->connect(false) ){
      ce_ = ConnNoError;
      connected_=true;
    }else{
      signal_error("Could not connect");
    }
  }

  void XmppConnection::send(std::string jid, std::string message){
    if( (connected_==true) && (ce_ == gloox::ConnNoError) ){

        using namespace gloox;
        
        Message m(Message::Chat, JID(jid), message);
        j->send(m);
      }
  }

  void XmppConnection::poll(){
    if( (connected_==true) && (ce_ == gloox::ConnNoError) ){
      ce_ = j->recv(1);
    }
  }

  /*
   * Callbacks...
   */

  void XmppConnection::handleDataForm(const gloox::JID&, const gloox::DataForm&){
    // ignore
  }
  void XmppConnection::handleOOB(const gloox::JID&, const gloox::OOB&){
    // ignore
  }

  void XmppConnection::handleRegistrationFields( const gloox::JID& from, int fields, std::string instructions )
  {
    printf( "fields: %d\ninstructions: %s\n", fields, instructions.c_str() );

    gloox::RegistrationFields vals;
    vals.username = nickname_;
    vals.password = password_;
    registration_->createAccount( fields, vals );
  }

  void XmppConnection::handleRegistrationResult( const gloox::JID& from, gloox::RegistrationResult result )
  {
    printf( "result: %d\n", result );

    if(result == gloox::RegistrationSuccess){
      authenticated_ = true;
      signal_connected();
    }else{
      signal_error("There was a problem registering on the server");
      j->disconnect();
    }
  }

  void XmppConnection::handleAlreadyRegistered( const gloox::JID& from )
  {
    signal_error("the account already exists");
    printf( "the account already exists.\n" );
  }

  void XmppConnection::onConnect(){
    printf( "connected!!!\n" );
  
    if(j->authed()){
      signal_connected();
      authenticated_ = true;
    }else if(registration_mode_){
      registration_->fetchRegistrationFields();
    }else{
      signal_error("Bad username / password");
      j->disconnect();
    }
  }

  void XmppConnection::onDisconnect( gloox::ConnectionError e ){
    printf( "disconnected: %d\n", e );

    if( e == gloox::ConnAuthenticationFailed ){
      printf( "disconnected: %s\n", j->authError() );
      signal_error("failed");
    }else if( e == gloox::ConnStreamError ){
      printf( "disconnected. stream error: %s\n", j->streamError());
      signal_error("failed");
    }else if (e == gloox::ConnStreamVersionError){
      printf( "disconnected. stream version error.");
      signal_error("failed");
    }

    signal_disconnected();

  }

  void XmppConnection::handlePresence(const gloox::Presence &presence){
    if(presence.subtype()==gloox::Presence::Available){
      std::cout << presence.from().bare() << " subscribed." << std::endl;
      subscribers_.insert(presence.from().bare());
    }else{
      std::cout << presence.from().bare() << " unsubscribed." << std::endl;
      subscribers_.erase(presence.from().bare());
    }
    
  }

  bool XmppConnection::onTLSConnect( const gloox::CertInfo& info ){
    printf( "connected!!!\n" );

    return true;
  }

  void XmppConnection::handleMessage(const gloox::Message& msg, gloox::MessageSession *session){
//    signal_message(session->target().bare(), msg.body().c_str());
    signal_message(msg.from().bare(), msg.body().c_str());
    //printf( "type: %d, subject: %s, message: %s, thread id: %s\n", msg.subtype(), msg.subject().c_str(), msg.body().c_str(), msg.thread().c_str() );
//    messages_.push_back(msg.body());
  }
  
  void XmppConnection::handleLog( gloox::LogLevel level, gloox::LogArea area, const std::string& message )
  {
    printf("log: level: %d, area: %d, %s\n", level, area, message.c_str() );
  }
  
}